package main

import (
	"fmt"
	"time"
)

func sum(s []int, c chan int) {
	ss := 0
	for _, v := range s {
		ss += v
	}
	c <- ss // MARK 送入 信道,如果有前面放的没接走 也会堵塞

	//MARK 主进程先结果 这边不一定轮到打印
	//time.Sleep(999999)
	//fmt.Println("sum end")
}

func main() {
	classicUse()

	chanSize()

	rangeClose()

	selectChanel()

	selectDefault()
}

func classicUse() {
	fmt.Println("==============经典使用===============")
	s := []int{7, 2, 8, -9, 4, 0}

	//MARK 各协程共享一个channel
	c := make(chan int)

	// 前后放到不同协程
	go sum(s[:len(s)/2], c)
	go sum(s[len(s)/2:], c)

	x, y := <-c, <-c //MARK  从 信道 中接收,如果还没有值放进去 就会堵塞
	fmt.Println("=============================sun:", x, y, x+y)
}

func selectDefault() {
	fmt.Println("==============select default===============")
	tick := time.Tick(100 * time.Millisecond)  //MARK 周期性
	boom := time.After(500 * time.Millisecond) //MARK 一次性的
	for {
		select {
		case <-tick:
			fmt.Println("tick.")
		case <-boom:
			fmt.Println("BOOM!")
			return // for 的出口
		default: //MARK 都没好走这
			fmt.Println("    .")
			time.Sleep(50 * time.Millisecond)
		}
	}
}

func selectChanel() {

	fmt.Println("==================selectChanel==============")
	c := make(chan int)
	quit := make(chan int)
	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println(<-c) //MARK 出信道
		}
		quit <- 0
	}()

	for {
		select { //MARK 可以等多个信道 , 阻塞到其中之一可执行, 都可执行就随机选一个执行
		case c <- 1: //MARK 放入信道
			fmt.Println("in")
		case a := <-quit: //MARK 拿出信道
			fmt.Printf("quit %v \n", a)
			return
		}
	}
}

func rangeClose() {

	fmt.Println("======================range and close=============================")
	c := make(chan int, 10)
	go fibonacci(cap(c), c) //MARK cap是拿到信道的容量
	for i := range c {      //MARK 直到信道被close
		fmt.Println(i)
	}
}

func fibonacci(n int, c chan int) {
	x, y := 0, 1
	for i := 0; i < n; i++ {
		c <- x //放太快超过容量 这边就会堵塞
		x, y = y, x+y
	}
	close(c) //MARK 让range不用等了
}

func chanSize() {
	fmt.Println("=============================chan Size =================")
	ch := make(chan int, 2) //MARK 如果这里是没2 就会报错 默认是1 放进去一个 就要等拿走 才能再放入第二个
	ch <- 1
	ch <- 2
	fmt.Println(<-ch)
	fmt.Println(<-ch)
	fmt.Printf("size%v\n", cap(ch))
}
